#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Final Hook - Complete Encryption Analysis
完整捕获数美SDK加密流程
"""

import frida
import sys
import time
import requests
import io

# Fix encoding for Windows console
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')

print("\n" + "="*80)
print("数美SDK - 完整加密流程捕获")
print("="*80 + "\n")

# 1. Connect to device
print("[1] 连接设备...")
try:
    device = frida.get_usb_device()
    print(f"    ✓ 已连接: {device}")
except Exception as e:
    print(f"    ✗ 连接失败: {e}")
    sys.exit(1)

# 2. Spawn McDonald's APP
print("\n[2] 启动麦当劳APP...")
package_name = "com.mcdonalds.gma.cn"

try:
    pid = device.spawn([package_name])
    print(f"    ✓ 已启动进程: {package_name} (PID: {pid})")
    session = device.attach(pid)
    print(f"    ✓ 已附加到 PID: {pid}")
except Exception as e:
    print(f"    ✗ 启动/附加失败: {e}")
    sys.exit(1)

# 3. Load hook script
print("\n[3] 加载Hook脚本...")
script_file = 'final_capture.js'
try:
    with open(script_file, 'r', encoding='utf-8') as f:
        script_code = f.read()
except Exception as e:
    print(f"    ✗ 读取脚本失败: {e}")
    sys.exit(1)

script = session.create_script(script_code)
print(f"    ✓ 脚本已创建")

# Captured data
captured_data = {
    'aes_keys': [],
    'rsa_plaintexts': [],
    'encrypted_devs': []
}

# Message handler
def on_message(message, data):
    if message['type'] == 'send':
        payload = message['payload']
        print(f"{payload}")
    elif message['type'] == 'error':
        print(f"\n[FRIDA ERROR] {message['description']}")
        if 'stack' in message:
            print(f"Stack: {message['stack']}")
    else:
        print(message)

script.on('message', on_message)
script.load()
print(f"    ✓ 已加载: {script_file}")

# Resume the spawned process
device.resume(pid)
print(f"    ✓ 已恢复进程运行")

# 4. Wait for hook initialization
print("\n[4] 等待Hook初始化...")
time.sleep(7)  # Give more time for the app to fully start and JS hooks to load
print("    ✓ Hook已就绪")

# 5. Call API to trigger encryption
print("\n" + "="*80)
print("[5] 调用API触发数美SDK加密...")
print("="*80 + "\n")

api_url = "http://120.27.155.222:9999/api/message/send-test"

for i in range(3):
    print(f"\n{'#'*80}")
    print(f"# API调用 {i+1}/3")
    print(f"{'#'*80}\n")
    
    try:
        print(f"[API] 调用: {api_url}")
        response = requests.get(api_url, timeout=10)
        
        if response.status_code == 200:
            data = response.json()
            print(f"\n[响应]")
            print(f"  Code: {data.get('code')}")
            print(f"  Msg: {data.get('msg')}")
            print(f"  Points: {data.get('points')}")
            
            dev_encrypted = data.get('dev', '')
            if dev_encrypted:
                print(f"\n[加密的dev字段]")
                print(f"  长度: {len(dev_encrypted)}")
                print(f"  值: {dev_encrypted}")
                
                # Decode base64 to see raw bytes
                import base64
                try:
                    dev_bytes = base64.b64decode(dev_encrypted)
                    print(f"  十六进制 (前64字节): {dev_bytes[:64].hex()}...")
                    print(f"  总字节数: {len(dev_bytes)}")
                except:
                    pass
                
                captured_data['encrypted_devs'].append(dev_encrypted)
        else:
            print(f"    ✗ API返回状态码: {response.status_code}")
            
    except Exception as e:
        print(f"    ✗ API调用失败: {e}")
    
    if i < 2:
        print(f"\n[*] 等待2秒后进行下一次调用...")
        time.sleep(2)

# 6. Wait for hook output
print("\n\n" + "="*80)
print("[6] 等待Hook输出 (5秒)...")
print("="*80)
time.sleep(5)

# 7. Summary
print("\n\n" + "="*80)
print("捕获摘要")
print("="*80 + "\n")

print(f"捕获的加密dev字段: {len(captured_data['encrypted_devs'])}")
for idx, dev in enumerate(captured_data['encrypted_devs'], 1):
    print(f"  {idx}. {dev[:50]}...")

# 8. Wait a bit more for any delayed messages
print("\n" + "="*80)
print("等待可能的延迟消息...")
print("="*80 + "\n")

time.sleep(3)

# Clean up
print("\n[+] 停止Hook...")
script.unload()
session.detach()
print("[OK] 已退出\n")

